<script lang="ts" setup>
import type {
  ResourceNode,
  RoleNodeDto,
  RoleOutDto,
  RoleResourceInDto,
} from '#/api/daprplus';

import { reactive, ref, watch } from 'vue';

import { Button, Drawer, message, TabPane, Tabs } from 'ant-design-vue';

import { getEntityResourceNodeApi, setRoleResourceApi } from '#/api/daprplus';
import {
  collectAllSelectedResourceIds,
  convertToRoleResourceDtos,
  extractSelectedResources,
  handleApiResult,
  hasAnyServiceChanges,
  initServiceChangesMap,
  serviceInfoDict,
} from '#/utils/daprplus';

import RoleResourceList from './RoleResourceList.vue';

const props = defineProps<{
  open: boolean;
  role: null | RoleNodeDto | RoleOutDto;
}>();

const emit = defineEmits<{
  save: [roleId: string, resourceIds: string[]];
  'update:open': [value: boolean];
}>();

// 服务列表
const services = Object.values(serviceInfoDict).map((info) => ({
  key: info.value,
  name: info.label,
}));

// 当前激活的Tab
const activeKey = ref<number | string>('identity-api');

// 资源树数据
const resourcesMap = ref<Record<string, ResourceNode[]>>({});
// 已选择的资源
const selectedResourcesMap = ref<Record<string, Record<string, ResourceNode>>>(
  {},
);
// 加载状态
const loadingMap = ref<Record<string, boolean>>({});
// 提交状态
const submitting = ref(false);
// 刷新状态
const refreshing = ref(false);
// 各服务的变更状态
const serviceChangesMap = ref<Record<string, boolean>>(
  initServiceChangesMap(services),
);
// 是否有任何变更
const hasAnyChanges = ref(false);
// 资源列表组件引用
const resourceListRefs = reactive<Record<string, any>>({});

// 监听open和role变化，重新加载数据
watch(
  () => [props.open, props.role],
  ([open, role]) => {
    if (open && role) {
      loadAllResources();
      // 重置变更状态
      resetChangesState();
    }
  },
  { immediate: true },
);

// 重置变更状态
function resetChangesState() {
  serviceChangesMap.value = initServiceChangesMap(services);
  hasAnyChanges.value = false;
}

// 处理服务变更事件
function handleServiceChanges(serviceKey: string, hasChanges: boolean) {
  serviceChangesMap.value[serviceKey] = hasChanges;
  updateHasAnyChanges();
}

// 更新整体变更状态
function updateHasAnyChanges() {
  hasAnyChanges.value = hasAnyServiceChanges(serviceChangesMap.value);
}

// 加载所有服务的资源树
async function loadAllResources() {
  if (!props.role || !props.role.id) return;

  try {
    // 设置所有服务为加载状态
    loadingMap.value = services.reduce(
      (acc, service) => {
        acc[service.key] = true;
        return acc;
      },
      {} as Record<string, boolean>,
    );

    // 重置数据
    resourcesMap.value = {};
    selectedResourcesMap.value = {};

    const result = await getEntityResourceNodeApi(props.role.id);

    // 更新所有服务的资源树和选中状态
    services.forEach((service) => {
      const resources = result[service.key] || [];
      resourcesMap.value[service.key] = resources;
      selectedResourcesMap.value[service.key] =
        extractSelectedResources(resources);
    });
  } catch (error) {
    console.error('加载资源失败:', error);
    message.error('加载资源失败');
  } finally {
    // 重置所有服务的加载状态
    loadingMap.value = services.reduce(
      (acc, service) => {
        acc[service.key] = false;
        return acc;
      },
      {} as Record<string, boolean>,
    );
  }
}

// 处理资源选中事件
function handleResourceSelected(
  serviceKey: string,
  resource: ResourceNode,
  selected: boolean,
) {
  if (!selectedResourcesMap.value[serviceKey]) {
    selectedResourcesMap.value[serviceKey] = {};
  }

  if (selected) {
    selectedResourcesMap.value[serviceKey][resource.id] = resource;
  } else {
    delete selectedResourcesMap.value[serviceKey][resource.id];
  }
}

// 处理操作选中事件
function handleOperationSelected(serviceKey: string, resource: ResourceNode) {
  // 确保服务键存在
  if (!selectedResourcesMap.value[serviceKey]) {
    selectedResourcesMap.value[serviceKey] = {};
  }

  // 确保资源在选中列表中
  if (resource.isSelected) {
    selectedResourcesMap.value[serviceKey][resource.id] = resource;
  }
}

// 关闭抽屉
function handleClose() {
  emit('update:open', false);
}

// 提交授权
async function handleSubmit() {
  if (!props.role) return;

  try {
    submitting.value = true;

    // 收集所有有变更的服务的授权数据
    const resourceDict: Record<string, RoleResourceInDto[]> = {};
    for (const service of services) {
      if (!serviceChangesMap.value[service.key]) {
        continue;
      }
      const selectedResources = selectedResourcesMap.value[service.key] || {};
      resourceDict[service.key] = convertToRoleResourceDtos(selectedResources);
    }

    // 一次性提交所有服务的授权
    const result = await setRoleResourceApi(props.role.id || '', resourceDict);
    handleApiResult(result);

    // 收集所有选中的资源ID
    const allResourceIds = collectAllSelectedResourceIds(
      selectedResourcesMap.value,
    );

    // 触发保存事件
    if (props.role && props.role.id) {
      emit('save', props.role.id.toString(), allResourceIds);
    }

    // 重置变更状态
    resetChangesState();

    // 更新各组件的原始状态
    for (const service of services) {
      if (
        resourceListRefs[service.key] &&
        resourceListRefs[service.key].resetOriginalState
      ) {
        resourceListRefs[service.key].resetOriginalState(
          resourcesMap.value[service.key] || [],
        );
      }
    }
  } catch (error) {
    console.error('保存授权失败:', error);
    message.error('保存授权失败');
  } finally {
    submitting.value = false;
  }
}

// 刷新数据
async function handleRefresh() {
  if (!props.role || !props.role.id) return;

  try {
    refreshing.value = true;
    await loadAllResources();
    // 重置变更状态
    resetChangesState();
    message.success('数据刷新成功');
  } catch (error) {
    console.error('刷新数据失败:', error);
    message.error('刷新数据失败');
  } finally {
    refreshing.value = false;
  }
}
</script>

<template>
  <Drawer
    :open="open"
    :title="$t('daprplus.auth.role.authTitle', { name: role?.name })"
    :width="800"
    @close="handleClose"
    @update:open="(val) => emit('update:open', val)"
  >
    <Tabs v-model:active-key="activeKey">
      <TabPane
        v-for="service in services"
        :key="service.key"
        :tab="service.name"
      >
        <RoleResourceList
          :resources="resourcesMap[service.key] || []"
          :loading="loadingMap[service.key] || false"
          :service-key="service.key"
          @resource-selected="
            (resource, selected) =>
              handleResourceSelected(service.key, resource, selected)
          "
          @operation-selected="
            (resource) => handleOperationSelected(service.key, resource)
          "
          @has-changes="
            (serviceKey, hasChanges) =>
              handleServiceChanges(serviceKey, hasChanges)
          "
          :ref="
            (el) => {
              if (el) resourceListRefs[service.key] = el;
            }
          "
        />
      </TabPane>
    </Tabs>
    <template #footer>
      <div class="flex justify-end">
        <Button class="mr-2" @click="handleRefresh" :loading="refreshing">
          {{ $t('daprplus.refresh') }}
        </Button>
        <Button class="mr-2" @click="handleClose">
          {{ $t('daprplus.cancel') }}
        </Button>
        <Button
          type="primary"
          :loading="submitting"
          @click="handleSubmit"
          :disabled="!hasAnyChanges"
        >
          {{ $t('daprplus.submit') }}
        </Button>
      </div>
    </template>
  </Drawer>
</template>
